﻿#include "cHtml.h"
#include <iostream>

#include "_utf.h"
#include "_string.h"
#include "cHtmlObject.h"

#if 1
#include<winsock.h>
#pragma comment(lib, "ws2_32.lib")
static std::string getHtml(const std::string& url)
{
	const int BUFFSIZE = BUFSIZ;
	WSADATA						WSAData = { 0 };
	SOCKET						sockfd;
	struct sockaddr_in			addr;
	struct hostent				*pURL;
	char						myurl[BUFFSIZE];
	char						*pHost = 0, *pGET = 0;
	char						host[BUFFSIZE], GET[BUFFSIZE];
	char						header[BUFFSIZE] = "";
	static char					text[BUFFSIZE];
	int							i;

	/*
	*        windows下使用socket必须用WSAStartup初始化，否则不能调用
	*/
	if (WSAStartup(MAKEWORD(2, 0), &WSAData))
	{
		printf("WSA failed\n");
		return "";
	}

	/*
	*        分离url中的主机地址和相对路径
	*/
	strcpy(myurl, url.c_str());
	for (pHost = myurl; *pHost != '/' && *pHost != '\0'; ++pHost);
	{
		if ((int)(pHost - myurl) == strlen(myurl))
		{
			strcpy(GET, "/");
		}
		else
		{
			strcpy(GET, pHost);
		}
	}
	*pHost = '\0';
	strcpy(host, myurl);
//	printf("%s\n%s%s\n\n", host, host, GET);

	/*
	*        设定socket参数,并未真正初始化
	*/
	sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	pURL = gethostbyname(host);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = *((unsigned long*)pURL->h_addr);
	addr.sin_port = htons(80);

	/*
	*        组织发送到web服务器的信息
	*        为何要发送下面的信息请参考HTTP协议的约定
	*/
	strcat(header, "GET ");
	strcat(header, GET);
	strcat(header, " HTTP/1.1\r\n");
	strcat(header, "HOST: ");
	strcat(header, host);
	strcat(header, "\r\nConnection: Close\r\n\r\n");

	/*
	*        连接到服务器，发送请求header，并接受反馈（即网页源代码）
	*/
	connect(sockfd, (SOCKADDR *)&addr, sizeof(addr));

	send(sockfd, header, strlen(header), 0);

	std::string str;
	while (recv(sockfd, text, BUFFSIZE, 0) > 0)
	{
//		printf("%s", text);
		str += text;
		memset(text, '\0', BUFFSIZE);
//		_strnset(text, '\0', BUFFSIZE);
	}

	closesocket(sockfd);
	WSACleanup();
	return str;
}

static std::string getHtml(const std::string& url, const std::string& url2)
{
	sockaddr_in sin;
	WSADATA wsadata;
	//WSAStartup()的调用方和Windows?Sockets?DLL互相通知对方它们可以支持的最高版本,??
	//并且互相确认对方的最高版本是可接受的.?在WSAStartup()函数的入口,??
	//Windows?Sockets?DLL检查了应用程序所需的版本.如果版本高于DLL支持的最低版本,??
	//则调用成功并且DLL在wHighVersion中返回它所支持的最高版本,??
	//在?wVersion中返回它的高版本和wVersionRequested中的较小者.??
	//然后Windows?Sockets?DLL就会假设应用程序将使用wVersion.??
	if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
	{
		std::cout << "startup failed\n" << std::endl;
		return "";
	}

	SOCKET sock = socket(PF_INET, SOCK_STREAM, 0);
	//?memset?是对一段内存空间全部设置为某个字符??
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(80);
	//sin.sin_addr.S_un.S_addr=inet_addr("203.208.37.99");??
	hostent* hptr = gethostbyname(url.c_str());
	if (hptr == nullptr)
	{
		std::cout << "ip failed\n" << std::endl;
		return "";
	}
	// 将有参数的string内容copy到左边参数
	memcpy(&sin.sin_addr.S_un.S_addr, hptr->h_addr, hptr->h_length);
	printf("ip:%d.%d.%d.%d\n", sin.sin_addr.S_un.S_un_b.s_b1,
		sin.sin_addr.S_un.S_un_b.s_b2,
		sin.sin_addr.S_un.S_un_b.s_b3,
		sin.sin_addr.S_un.S_un_b.s_b4);
	//?将sockaddr_in?transfer?to?sockaddr??
	if (connect(sock, (sockaddr*)&sin, sizeof(sin)))
	{
		std::cout << "connect failed\n" << std::endl;
		return "";
	}
	else
	{
		std::cout << "connect success\n" << std::endl;
	}
	// 	string?ss;?
	// 	int?len?=?recv(s,const_cast<char*>(ss.c_str()),2000,0);
	char buff[0xFFFF] = "GET /?st=1 HTTP/1.1\r\nHost:";
	strcat(buff, url.c_str());
	strcat(buff, url2.c_str());
	strcat(buff, "\r\nConnection:Close\r\n\r\n");
	send(sock, buff, strlen(buff), 0);
	int len = recv(sock, buff, 0xFFFF, 0);
	printf("the length of page is %d\n", len);
	if (len == -1)
	{
		std::cout << "receive failed\n" << std::endl;
		return "";
	}
	for (int i = 0; i < len; i++)
	{
		printf("%c", buff[i]);
	}
	WSACleanup();
	closesocket(sock);
	return std::string(buff, len);
}
#else
#include <windows.h>
#include <wininet.h>
#define MAXSIZE 1024
#pragma comment(lib, "Wininet.lib")
#define MAX_LOADSTRING 100


static std::string getHtml(const std::string& url)
{
	HINTERNET hINet = InternetOpen("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);    //InternetOpen初始化WININET.DLL
	if (!hINet)
	{
		std::cout << "InternetOpen fail" << std::endl;
		return "";
	}
	HINTERNET hHttpFile = InternetOpenUrl(hINet, url.c_str(), NULL, 0, /*0*/INTERNET_FLAG_DONT_CACHE, 0);  //这个函数连接到一个网络服务器上并且最被从服务器上读取数据
	if (!hHttpFile)
	{
		std::cout << "error open url" << std::endl;
		return "";
	}

	char szSizeBuffer[512];
	DWORD dwLengthSizeBuffer = sizeof(szSizeBuffer);
	LPDWORD lpdwIndex = 0;
	//	DWORD dwBuffer = 0;
	//	DWORD dwSize = sizeof(dwBuffer);
	BOOL bQuery = HttpQueryInfo(hHttpFile, HTTP_QUERY_CONTENT_LENGTH, szSizeBuffer, &dwLengthSizeBuffer, /*NULL*/lpdwIndex); //得到关于文件的信息
//	BOOL bQuery = HttpQueryInfo(hHttpFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwBuffer, &dwSize, NULL); //得到关于文件的信息
	if (bQuery == false)
	{
		InternetCloseHandle(hINet);

		std::cout << "error query info" << std::endl;
		return "";
	}

	int FileSize = atol(szSizeBuffer);    //atol函数把字符串转换成长整型数
	std::string revData;
	revData.resize(FileSize);
	DWORD dwBytesRead;
	BOOL bRead = InternetReadFile(hHttpFile, &revData[0], FileSize, &dwBytesRead);     //web浏览器将在InternetReadFile上循环 ，不停地从Internet上读入数据块。
	if (!bRead)
	{
		std::cout << "error to read file" << std::endl;
		return "";
	}
	// 	std::ofstream out_file("duhui.txt");
	// 	out_file << revData;              //输出到文件

	InternetCloseHandle(hHttpFile);   //关闭句柄
	InternetCloseHandle(hINet);
	std::cout << "get html ok!/n" << std::endl;
	return revData;
}
#endif


//////////////////////////////////////////////////////////////////////////
static const char* g_space = " ", *g_enter = "\n";
void sUnit::read(std::ifstream& ifile)
{
	ifile >> code >> gotoo >> click >> tag;
}

void sUnit::write(std::ofstream& ofile, const char* sapce_enter) const
{
	ofile << code << g_space << gotoo << g_space << click << g_space << tag << sapce_enter;
}


//////////////////////////////////////////////////////////////////////////
void sBuilding::read(std::ifstream& ifile)
{
	sUnit::read(ifile);
	int size;
	ifile >> tag2 >> size;
	units.resize(size);
	std::string line;
	getline(ifile, line);
	for (int k = 0, size = units.size(); k < size; ++k)
	{
		units.at(k).read(ifile);
		getline(ifile, line);
	}
}

void sBuilding::write(std::ofstream& ofile) const
{
	sUnit::write(ofile, g_space);
	ofile << tag2 << g_space << units.size() << g_enter;
	for (int k = 0, size = units.size(); k < size; ++k)
	{
		units.at(k).write(ofile, g_enter);
	}
}


//////////////////////////////////////////////////////////////////////////
void sInfo::read(std::ifstream& ifile)
{
	sUnit::read(ifile);
	int size;
	ifile >> addr >> operid >> size;
	buildings.resize(size);
	std::string line;
	getline(ifile, line);
	for (int k = 0, size = buildings.size(); k < size; ++k)
	{
		buildings.at(k).read(ifile);
	}
}

void sInfo::write(std::ofstream& ofile) const
{
	sUnit::write(ofile, g_space);
	ofile << addr << g_space << operid << g_space << buildings.size() << g_enter;
	for (int k = 0, size = buildings.size(); k < size; ++k)
	{
		buildings.at(k).write(ofile);
	}
}


//////////////////////////////////////////////////////////////////////////
std::string cHtml::getOperid(const std::string& url)
{
	std::vector<std::string> strs;
	cc::split(url, "=", strs);
	return strs.at(1).substr(0, strs.at(1).length() - strlen("&systemid"));
}

std::string cHtml::getHtml(const std::string& url)
{
	return ::getHtml(url);
}


//////////////////////////////////////////////////////////////////////////
static cHtmlObject object;
sInfo cHtml::getInfo(const std::string& html)
{
	object.load(html);
	const cHtmlObject::cNode* node = object.getHead(), *nodeRight = nullptr;
	std::string key, keyRight, value, valueRight, str;
	std::vector<std::string> strs;
	sInfo info;
	while (true)
	{
		if (node == nullptr)
		{
			break;
		}
		key = toStr(node->key);
		value = toGBK(node->value);

		nodeRight = node->right;
		while (true)
		{
			if (nodeRight == nullptr)
			{
				break;
			}
			keyRight = toStr(nodeRight->key);
			valueRight = toStr(nodeRight->value);
			if (keyRight == "onclick" && !valueRight.empty())
			{
				std::cout << valueRight << "\t";
				cc::split(valueRight, "'", strs);
				sUnit* unit = nullptr;
				if (info.code.empty())
				{
				//	info.click = strs.at(3);
					unit = &info;
				}
				else
				{
					sBuilding building;
					building.click = strs.at(3);
					info.buildings.push_back(building);
					unit = &info.buildings.back();	
				}
				unit->code = strs.at(1);
				str = strs.at(0);
				str.pop_back();
				cc::split(str, "_", strs);
				unit->gotoo = strs.at(1);
			}
			nodeRight = nodeRight->right;
		} 
		if (key == "div" && !value.empty())
		{
			std::cout << value << std::endl;
			if (info.addr.empty())
			{
				info.addr = value;
			}
			else if (info.tag.empty())
			{
				info.tag = value;
			}
			else
			{
				info.buildings.back().tag = value;
			}
		}
		node = node->next;
	}
	return info;
}


void cHtml::getInfo(const std::string& html, sBuilding& building)
{
	object.load(html);
	const cHtmlObject::cNode* node = object.getHead(), *nodeRight = nullptr;
	std::string key, keyRight, value, valueRight, str;
	std::vector<std::string> strs;
	int i = 0;
	while (true)
	{
		if (node == nullptr)
		{
			break;
		}
		key = toStr(node->key);
		value = toGBK(node->value);

		nodeRight = node->right;
		while (true)
		{
			if (nodeRight == nullptr)
			{
				break;
			}
			keyRight = toStr(nodeRight->key);
			valueRight = toStr(nodeRight->value);
			if (keyRight == "onclick" && !valueRight.empty())
			{
				std::cout << valueRight << "\t";
				if (building.tag2.empty() || building.tag2 == building.tag)
				{
				}
				else
				{
					cc::split(valueRight, "'", strs);
					sUnit unit;
					unit.code = strs.at(1);
					str = strs.at(0);
					str.pop_back();
					cc::split(str, "_", strs);
					unit.gotoo = strs.at(1);
					building.units.push_back(unit);
				}
			}
 			nodeRight = nodeRight->right;
		}
		if (key == "div" && !value.empty())
		{
			std::cout << value << std::endl;
			if (building.tag2.empty())
			{
				building.tag2 = building.tag;
			}
			else if (building.tag2 == building.tag)
			{
				building.tag2 = value;
			}
			else
			{
				building.units.back().tag = value;
			}
		}
		node = node->next;
	}
}


std::string cHtml::toStr(const char* str)
{
	return str == nullptr ? "" : str;
}


std::string cHtml::toGBK(const char* str)
{
	return str == nullptr ? "" : cc::utf2gbk(std::string(str));
}

